package com.anttribe.components.infra.lang.reflect;

import com.anttribe.components.infra.lang.reflect.scanner.ClassScannerExecutor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

/**
 * @author zhaoyong
 * @date 2021/11/4 0004
 */
public final class ClassScannerUtils {

    /**
     * 扫描指定包下的类
     *
     * @param basePackage 包名
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanClasses(String basePackage) {
        return ClassScannerUtils.scanClasses(basePackage, null);
    }

    /**
     * 扫描指定包下的类
     *
     * @param basePackage 包名
     * @param predicate   筛选类
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanClasses(String basePackage, Predicate<Class<?>> predicate) {
        return new ClassScannerExecutor().scan(basePackage, predicate);
    }

    /**
     * 指定父类，扫描出继承的子类
     *
     * @param superClass 父类
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanSubClasses(Class<?> superClass) {
        return ClassScannerUtils.scanSubClasses(superClass, ReflectUtils.getPackageName(superClass));
    }

    /**
     * 指定父类，扫描出实现的子类
     *
     * @param superClass 父类
     * @param predicate  筛选类
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanSubClasses(Class<?> superClass, Predicate<Class<?>> predicate) {
        return ClassScannerUtils.scanSubClasses(superClass, predicate, ReflectUtils.getPackageName(superClass));
    }

    /**
     * 指定父类，扫描出继承的子类
     *
     * @param superClass   父类
     * @param basePackages 待扫描的包
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanSubClasses(Class<?> superClass, String... basePackages) {
        return ClassScannerUtils.scanSubClasses(superClass, null, basePackages);
    }

    /**
     * 指定父类，扫描出继承的子类
     *
     * @param superClass   父类
     * @param predicate    筛选类
     * @param basePackages 待扫描的包
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanSubClasses(Class<?> superClass, Predicate<Class<?>> predicate, String... basePackages) {
        List<String> scanBasePackages = new ArrayList<>();
        if (!ArrayUtils.isEmpty(basePackages)) {
            CollectionUtils.addAll(scanBasePackages, basePackages);
        }

        if (CollectionUtils.isEmpty(scanBasePackages)) {
            scanBasePackages.add(ReflectUtils.getPackageName(superClass));
        }

        Set<Class<?>> scanSubClasses = new HashSet<>();
        scanBasePackages.stream().forEach(scanBasePackage -> {
            ClassScannerExecutor classScannerExecutor = new ClassScannerExecutor();
            Set<Class<?>> scanClasses = classScannerExecutor.scan(scanBasePackage, (aClass) -> {
                Type superClassType = aClass.getGenericSuperclass();
                if ((null != superClassType && superClassType.equals(superClass)) && (null != predicate && predicate.test(aClass))) {
                    return true;
                }
                return false;
            });
            if (!CollectionUtils.isEmpty(scanClasses)) {
                scanSubClasses.addAll(scanClasses);
            }
        });

        return scanSubClasses;
    }

    /**
     * 指定接口，扫描出实现类
     *
     * @param interfaces 接口
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanImplClasses(Class<?>[] interfaces) {
        return ClassScannerUtils.scanImplClasses(interfaces, ReflectUtils.getPackageName(ClassScannerUtils.class));
    }

    /**
     * 指定父类，扫描出继承的子类
     *
     * @param interfaces   父类
     * @param basePackages 待扫描的包
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanImplClasses(Class<?>[] interfaces, String... basePackages) {
        return ClassScannerUtils.scanImplClasses(interfaces, aClass -> Boolean.TRUE, ReflectUtils.getPackageName(ClassScannerUtils.class));
    }

    /**
     * 指定父类，扫描出实现的子类
     *
     * @param interfaces 接口
     * @param predicate  筛选类
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanImplClasses(Class<?>[] interfaces, Predicate<Class<?>> predicate) {
        return ClassScannerUtils.scanImplClasses(interfaces, predicate, ReflectUtils.getPackageName(ClassScannerUtils.class));
    }

    /**
     * 指定父类，扫描出继承的子类
     *
     * @param interfaces   接口
     * @param predicate    筛选类
     * @param basePackages 待扫描的包
     * @return Set<Class < ?>>
     */
    public static Set<Class<?>> scanImplClasses(Class<?>[] interfaces, Predicate<Class<?>> predicate, String... basePackages) {
        List<String> scanBasePackages = new ArrayList<>();
        if (!ArrayUtils.isEmpty(basePackages)) {
            CollectionUtils.addAll(scanBasePackages, basePackages);
        }

        if (CollectionUtils.isEmpty(scanBasePackages)) {
            Arrays.stream(interfaces).forEach(intf -> {
                scanBasePackages.add(ReflectUtils.getPackageName(intf));
            });
        }

        Set<Class<?>> scanImplClasses = new HashSet<>();
        scanBasePackages.stream().forEach(scanBasePackage -> {
            Set<Class<?>> scanClasses = new ClassScannerExecutor().scan(scanBasePackage, (aClass) -> {
                Type[] genericInterfaces = aClass.getGenericInterfaces();
                if ((!ArrayUtils.isEmpty(genericInterfaces) && CollectionUtils.containsAll(Arrays.asList(genericInterfaces), Arrays.asList(interfaces))) && (null != predicate && predicate.test(aClass))) {
                    return true;
                }
                return false;
            });
            if (!CollectionUtils.isEmpty(scanClasses)) {
                scanImplClasses.addAll(scanClasses);
            }
        });

        return scanImplClasses;
    }

}
